package iammert.com.library;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.LayoutScatter;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

/**
 * Created by mertsimsek on 26/01/17.
 */
public class StatusView extends DependentLayout {
    private static final int DISMISS_ON_COMPLETE_DELAY = 2000;
    private static final String DISMISS_ON_COMPLETE = "dismissOnComplete";
    private static final String COMPLETE = "complete";
    private static final String ERROR = "error";
    private static final String LOADING = "loading";

    /**
     * Current status of status view
     */
    private Status currentStatus;

    /**
     * Automatically hide when status changed to complete
     */
    private boolean hideOnComplete;

    /**
     * Views for each status
     */
    private Component completeView;
    private Component errorView;
    private Component loadingview;

    /**
     * Fade in out animations
     */
    private AnimatorProperty slideOut;
    private AnimatorProperty slideIn;

    /**
     * layout inflater
     */
    private LayoutScatter inflater;

    /**
     * Handler
     */
    private EventHandler handler;
    private static int durationTime = 300;

    /**
     * Auto dismiss on complete
     */
    private Runnable autoDismissOnComplete = new Runnable() {
        @Override
        public void run() {
            exitAnimation(getCurrentComponent(currentStatus));
            handler.removeTask(autoDismissOnComplete);
        }
    };

    public StatusView(Context context) {
        super(context);
        init(context, null, 0, 0, 0);
    }

    public StatusView(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context, attrs, 0, 0, 0);
    }

    public StatusView(Context context, int completeLayout, int errorLayout, int loadingLayout) {
        super(context);
        init(context, null, completeLayout, errorLayout, loadingLayout);
    }

    public StatusView(Context context, AttrSet attrs, int completeLayout, int errorLayout, int loadingLayout) {
        super(context, attrs);
        init(context, attrs, completeLayout, errorLayout, loadingLayout);
    }

    private void init(Context context, AttrSet attrs, int completeLayout, int errorLayout, int loadingLayout) {
        /**
         * Load initial values
         */
        currentStatus = Status.IDLE;
        hideOnComplete = true;
        inflater = LayoutScatter.getInstance(context);
        handler = new EventHandler(EventRunner.getMainEventRunner());
        boolean hasParam = attrs.getAttr(DISMISS_ON_COMPLETE).isPresent();
        if (hasParam) {
            hideOnComplete = attrs.getAttr(DISMISS_ON_COMPLETE).get().getBoolValue();
        }
        int completeLayoutId = 0;
        int errorLayoutId = 0;
        int loadingLayoutId = 0;
        String value = null;
        hasParam = attrs.getAttr(COMPLETE).isPresent();
        if (hasParam) {
            value = attrs.getAttr(COMPLETE).get().getStringValue();
            if (value != null && value.length() > 0 && value.contains(":")) {
                completeLayoutId = Integer.valueOf(value.split(":")[1]);
            }
        }
        hasParam = attrs.getAttr(ERROR).isPresent();
        if (hasParam) {
            value = attrs.getAttr(ERROR).get().getStringValue();
            if (value != null && value.length() > 0 && value.contains(":")) {
                errorLayoutId = Integer.valueOf(value.split(":")[1]);
            }
        }
        hasParam = attrs.getAttr(LOADING).isPresent();
        if (hasParam) {
            value = attrs.getAttr(LOADING).get().getStringValue();
            if (value != null && value.length() > 0 && value.contains(":")) {
                loadingLayoutId = Integer.valueOf(value.split(":")[1]);
            }
        }
        /**
         * inflate layouts
         */
        if (completeLayoutId != 0) {
            completeView = inflater.parse(completeLayoutId, null, false);
            errorView = inflater.parse(errorLayoutId, null, false);
            loadingview = inflater.parse(loadingLayoutId, null, false);
        } else {
            completeView = inflater.parse(completeLayout, null, false);
            errorView = inflater.parse(errorLayout, null, false);
            loadingview = inflater.parse(loadingLayout, null, false);
        }
        /**
         * Default layout params
         */
        completeView.setLayoutConfig(new DependentLayout.LayoutConfig(DependentLayout.LayoutConfig.MATCH_PARENT, DependentLayout.LayoutConfig.MATCH_PARENT));
        errorView.setLayoutConfig(new DependentLayout.LayoutConfig(DependentLayout.LayoutConfig.MATCH_PARENT, DependentLayout.LayoutConfig.MATCH_PARENT));
        loadingview.setLayoutConfig(new DependentLayout.LayoutConfig(DependentLayout.LayoutConfig.MATCH_PARENT, DependentLayout.LayoutConfig.MATCH_PARENT));
        /**
         * Add layout to root
         */
        addComponent(completeView);
        addComponent(errorView);
        addComponent(loadingview);
        /**
         * set visibilities of childs
         */
        completeView.setVisibility(Component.INVISIBLE);
        errorView.setVisibility(Component.INVISIBLE);
        loadingview.setVisibility(Component.INVISIBLE);
    }

    public void setOnErrorClickListener(ClickedListener onErrorClickListener) {
        errorView.setClickedListener(onErrorClickListener);
    }

    public void setOnLoadingClickListener(ClickedListener onLoadingClickListener) {
        loadingview.setClickedListener(onLoadingClickListener);
    }

    public void setOnCompleteClickListener(ClickedListener onCompleteClickListener) {
        completeView.setClickedListener(onCompleteClickListener);
    }

    public Component getErrorView() {
        return errorView;
    }

    public Component getCompleteView() {
        return completeView;
    }

    public Component getLoadingView() {
        return loadingview;
    }

    public void setStatus(final Status status) {
        if (currentStatus == Status.IDLE) {
            currentStatus = status;
            enterAnimation(getCurrentComponent(currentStatus));
        } else if (status != Status.IDLE) {
            switchAnimation(getCurrentComponent(currentStatus), getCurrentComponent(status));
            currentStatus = status;
        } else {
            exitAnimation(getCurrentComponent(currentStatus));
        }
        handler.removeAllEvent();
        if (status == Status.COMPLETE && hideOnComplete) {
            handler.postTask(autoDismissOnComplete, DISMISS_ON_COMPLETE_DELAY);
        }
    }

    /**
     * 获取当前状态
     *
     * @return Status object
     */
    public Status getStatus() {
        return this.currentStatus;
    }

    private Component getCurrentComponent(Status status) {
        if (status == Status.IDLE) {
            return null;
        } else if (status == Status.COMPLETE) {
            return completeView;
        } else if (status == Status.ERROR) {
            return errorView;
        } else if (status == Status.LOADING) {
            return loadingview;
        }
        return null;
    }

    private void switchAnimation(final Component exitView, final Component enterView) {
        exitView.setVisibility(Component.VISIBLE);
        if (slideOut == null) {
            slideOut = new AnimatorProperty(exitView);
            slideOut.moveFromY(0).moveToY(-exitView.getHeight()).setDuration(durationTime);
        } else {
            slideOut.setTarget(enterView);
        }
        slideOut.setStateChangedListener(new SimpleAnimListener() {

            @Override
            public void onEnd(Animator animator) {
                exitView.setVisibility(Component.INVISIBLE);
                enterView.setVisibility(Component.VISIBLE);
                slideIn.setTarget(enterView);
                slideIn.start();
            }

        });
        slideOut.start();
    }

    private void enterAnimation(Component enterView) {
        if (enterView == null) {
            return;
        }
        enterView.setVisibility(VISIBLE);
        if (slideIn == null) {
            slideIn = new AnimatorProperty(enterView);
            slideIn.moveFromY(-enterView.getHeight()).moveToY(0).setDuration(durationTime);
        } else {
            slideIn.setTarget(enterView);
        }
        slideIn.start();
    }

    private void exitAnimation(final Component exitView) {
        if (exitView == null) {
            return;
        }
        if (slideOut == null) {
            slideOut = new AnimatorProperty(exitView);
            slideOut.moveFromY(0).moveToY(-exitView.getHeight()).setDuration(durationTime);
        } else {
            slideOut.setTarget(exitView);
        }
        slideOut.setStateChangedListener(new SimpleAnimListener() {

            @Override
            public void onEnd(Animator animator) {
                currentStatus = Status.IDLE;
                exitView.setVisibility(Component.INVISIBLE);
            }

        });
        slideOut.start();
    }
}
